#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Service Launcher 配置分析器
分析 config.yaml 中的服务配置，检查哪些服务可以运行
"""

import yaml
import os
import subprocess
import sys
from pathlib import Path
from typing import Dict, List, Tuple

class ServiceAnalyzer:
    def __init__(self, config_path: str = "config/config.yaml"):
        """
        初始化服务分析器
        
        Args:
            config_path: 配置文件路径
        """
        self.config_path = config_path
        self.services = []
        self.results = {
            'runnable': [],
            'issues': [],
            'missing_files': [],
            'ros_issues': []
        }
    
    def load_config(self) -> bool:
        """加载配置文件"""
        try:
            with open(self.config_path, 'r', encoding='utf-8') as file:
                config = yaml.safe_load(file)
                self.services = config.get('services', [])
                print(f"✅ 成功加载配置文件: {self.config_path}")
                print(f"📊 找到 {len(self.services)} 个服务配置")
                return True
        except FileNotFoundError:
            print(f"❌ 配置文件不存在: {self.config_path}")
            return False
        except yaml.YAMLError as e:
            print(f"❌ YAML格式错误: {e}")
            return False
        except Exception as e:
            print(f"❌ 加载配置文件时出错: {e}")
            return False
    
    def expand_path(self, path: str) -> str:
        """展开路径中的波浪号和环境变量"""
        if path.startswith('~/'):
            return os.path.expanduser(path)
        return os.path.expandvars(path)
    
    def check_python_service(self, service: Dict) -> Tuple[bool, str]:
        """检查Python服务"""
        script_path = service.get('script_path', '')
        
        if not script_path:
            return False, "缺少 script_path 字段"
        
        # 展开路径
        full_path = self.expand_path(script_path)
        
        # 检查文件是否存在
        if not os.path.exists(full_path):
            return False, f"脚本文件不存在: {full_path}"
        
        # 检查文件是否可执行或是Python文件
        if not (os.access(full_path, os.X_OK) or full_path.endswith('.py')):
            return False, f"文件不可执行且不是Python文件: {full_path}"
        
        # 检查工作目录（如果指定）
        working_dir = service.get('working_dir')
        if working_dir:
            full_working_dir = self.expand_path(working_dir)
            if not os.path.exists(full_working_dir):
                return False, f"工作目录不存在: {full_working_dir}"
        
        return True, f"Python脚本可用: {full_path}"
    
    def check_ros_environment(self) -> bool:
        """检查ROS环境是否可用"""
        try:
            # 检查ROS环境变量
            ros_distro = os.environ.get('ROS_DISTRO')
            if not ros_distro:
                return False
            
            # 尝试运行roscore --help来检查ROS是否安装
            result = subprocess.run(['roscore', '--help'], 
                                  capture_output=True, 
                                  text=True, 
                                  timeout=5)
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return False
    
    def check_ros_package(self, package_name: str) -> bool:
        """检查ROS包是否存在"""
        try:
            result = subprocess.run(['rospack', 'find', package_name], 
                                  capture_output=True, 
                                  text=True, 
                                  timeout=5)
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError):
            return False
    
    def check_rosrun_service(self, service: Dict) -> Tuple[bool, str]:
        """检查rosrun服务"""
        package = service.get('package', '')
        node = service.get('node', '')
        
        if not package:
            return False, "缺少 package 字段"
        if not node:
            return False, "缺少 node 字段"
        
        # 检查ROS环境
        if not self.check_ros_environment():
            return False, "ROS环境不可用"
        
        # 检查包是否存在
        if not self.check_ros_package(package):
            return False, f"ROS包不存在: {package}"
        
        # 检查工作目录（如果指定）
        working_dir = service.get('working_dir')
        if working_dir:
            full_working_dir = self.expand_path(working_dir)
            if not os.path.exists(full_working_dir):
                return False, f"工作目录不存在: {full_working_dir}"
        
        return True, f"ROS节点可用: {package}/{node}"
    
    def check_roslaunch_service(self, service: Dict) -> Tuple[bool, str]:
        """检查roslaunch服务"""
        package = service.get('package', '')
        launch_file = service.get('launch_file', '')
        
        if not package:
            return False, "缺少 package 字段"
        if not launch_file:
            return False, "缺少 launch_file 字段"
        
        # 检查ROS环境
        if not self.check_ros_environment():
            return False, "ROS环境不可用"
        
        # 检查包是否存在
        if not self.check_ros_package(package):
            return False, f"ROS包不存在: {package}"
        
        # 尝试找到launch文件
        try:
            result = subprocess.run(['rospack', 'find', package], 
                                  capture_output=True, 
                                  text=True, 
                                  timeout=5)
            if result.returncode == 0:
                package_path = result.stdout.strip()
                launch_path = os.path.join(package_path, 'launch', launch_file)
                if not os.path.exists(launch_path):
                    return False, f"Launch文件不存在: {launch_path}"
        except (subprocess.TimeoutExpired, FileNotFoundError):
            pass  # 无法验证launch文件，但包存在
        
        # 检查工作目录（如果指定）
        working_dir = service.get('working_dir')
        if working_dir:
            full_working_dir = self.expand_path(working_dir)
            if not os.path.exists(full_working_dir):
                return False, f"工作目录不存在: {full_working_dir}"
        
        return True, f"ROS Launch文件可用: {package}/{launch_file}"
    
    def analyze_service(self, service: Dict) -> None:
        """分析单个服务"""
        name = service.get('name', '未命名服务')
        service_type = service.get('type', '')
        
        print(f"\n🔍 分析服务: {name}")
        print(f"   类型: {service_type}")
        
        if service_type == 'python':
            is_runnable, message = self.check_python_service(service)
        elif service_type == 'rosrun':
            is_runnable, message = self.check_rosrun_service(service)
        elif service_type == 'roslaunch':
            is_runnable, message = self.check_roslaunch_service(service)
        else:
            is_runnable, message = False, f"未知的服务类型: {service_type}"
        
        print(f"   结果: {'✅' if is_runnable else '❌'} {message}")
        
        # 记录结果
        service_info = {
            'name': name,
            'type': service_type,
            'message': message,
            'config': service
        }
        
        if is_runnable:
            self.results['runnable'].append(service_info)
        else:
            self.results['issues'].append(service_info)
            
            # 分类问题类型
            if '不存在' in message:
                self.results['missing_files'].append(service_info)
            elif 'ROS' in message:
                self.results['ros_issues'].append(service_info)
    
    def print_summary(self) -> None:
        """打印分析摘要"""
        total = len(self.services)
        runnable = len(self.results['runnable'])
        issues = len(self.results['issues'])
        
        print("\n" + "="*60)
        print("📋 分析摘要")
        print("="*60)
        print(f"总服务数: {total}")
        print(f"可运行: {runnable} ({'✅' if runnable > 0 else '❌'})")
        print(f"有问题: {issues} ({'❌' if issues > 0 else '✅'})")
        
        if self.results['runnable']:
            print(f"\n✅ 可运行的服务 ({len(self.results['runnable'])}):")
            for service in self.results['runnable']:
                print(f"   • {service['name']} ({service['type']})")
        
        if self.results['issues']:
            print(f"\n❌ 有问题的服务 ({len(self.results['issues'])}):")
            for service in self.results['issues']:
                print(f"   • {service['name']} ({service['type']}): {service['message']}")
        
        # 问题分类统计
        if self.results['missing_files']:
            print(f"\n📁 文件缺失问题 ({len(self.results['missing_files'])}):")
            for service in self.results['missing_files']:
                print(f"   • {service['name']}")
        
        if self.results['ros_issues']:
            print(f"\n🤖 ROS相关问题 ({len(self.results['ros_issues'])}):")
            for service in self.results['ros_issues']:
                print(f"   • {service['name']}")
    
    def generate_report(self, output_file: str = "service_analysis_report.md") -> None:
        """生成详细的分析报告"""
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("# Service Launcher 分析报告\n\n")
            f.write(f"**分析时间**: {os.popen('date').read().strip()}\n")
            f.write(f"**配置文件**: {self.config_path}\n\n")
            
            # 摘要
            total = len(self.services)
            runnable = len(self.results['runnable'])
            issues = len(self.results['issues'])
            
            f.write("## 摘要\n\n")
            f.write(f"- 总服务数: {total}\n")
            f.write(f"- 可运行: {runnable}\n")
            f.write(f"- 有问题: {issues}\n\n")
            
            # 可运行服务
            if self.results['runnable']:
                f.write("## ✅ 可运行的服务\n\n")
                for service in self.results['runnable']:
                    f.write(f"### {service['name']}\n")
                    f.write(f"- **类型**: {service['type']}\n")
                    f.write(f"- **状态**: {service['message']}\n")
                    f.write(f"- **配置**:\n```yaml\n{yaml.dump(service['config'], default_flow_style=False, allow_unicode=True)}```\n\n")
            
            # 有问题的服务
            if self.results['issues']:
                f.write("## ❌ 有问题的服务\n\n")
                for service in self.results['issues']:
                    f.write(f"### {service['name']}\n")
                    f.write(f"- **类型**: {service['type']}\n")
                    f.write(f"- **问题**: {service['message']}\n")
                    f.write(f"- **配置**:\n```yaml\n{yaml.dump(service['config'], default_flow_style=False, allow_unicode=True)}```\n\n")
        
        print(f"\n📄 详细报告已生成: {output_file}")
    
    def run_analysis(self) -> None:
        """运行完整分析"""
        print("🚀 开始分析 Service Launcher 配置...")
        
        if not self.load_config():
            return
        
        # 检查ROS环境
        ros_available = self.check_ros_environment()
        print(f"🤖 ROS环境: {'✅ 可用' if ros_available else '❌ 不可用'}")
        
        # 分析每个服务
        for service in self.services:
            self.analyze_service(service)
        
        # 打印摘要
        self.print_summary()
        
        # 生成报告
        self.generate_report()

def main():
    """主函数"""
    # 检查配置文件路径
    config_path = "config/config.yaml"
    if len(sys.argv) > 1:
        config_path = sys.argv[1]
    
    analyzer = ServiceAnalyzer(config_path)
    analyzer.run_analysis()

if __name__ == "__main__":
    main() 